using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using JGSY.CMS.LowCode.Platform.Application.DTOs;
using JGSY.CMS.LowCode.Platform.Application.Interfaces;
using JGSY.CMS.LowCode.Platform.Domain.Entities;
using JGSY.CMS.LowCode.Platform.Domain.Interfaces;

namespace JGSY.CMS.LowCode.Platform.Application.Services
{
    /// <summary>
    /// 文章应用服务实现
    /// 提供文章的完整生命周期管理，包括创建、编辑、发布、删除、搜索和统计等功能
    /// 支持文章状态管理、分类关联、标签管理、批量操作等业务场景
    /// </summary>
    public class ArticleAppService : IArticleAppService
    {
        /// <summary>
        /// 文章数据仓储
        /// </summary>
        private readonly IArticleRepository _articleRepository;
        
        /// <summary>
        /// 日志记录器
        /// </summary>
        private readonly ILogger<ArticleAppService> _logger;

        /// <summary>
        /// 初始化文章应用服务实例
        /// </summary>
        /// <param name="articleRepository">文章数据仓储</param>
        /// <param name="logger">日志记录器</param>
        /// <exception cref="ArgumentNullException">当依赖项为null时抛出</exception>
        public ArticleAppService(
            IArticleRepository articleRepository,
            ILogger<ArticleAppService> logger)
        {
            _articleRepository = articleRepository ?? throw new ArgumentNullException(nameof(articleRepository));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }
        /// <summary>
        /// 批量删除文章
        /// 遍历指定的文章ID列表，执行软删除或物理删除操作
        /// </summary>
        /// <param name="ids">要删除的文章ID集合</param>
        /// <returns>实际删除的文章数量</returns>
        /// <exception cref="InvalidOperationException">当删除操作失败时抛出</exception>
        public async Task<int> BatchDeleteAsync(IEnumerable<long> ids)
        {
            try
            {
                var deletedCount = 0;
                foreach (var id in ids)
                {
                    var article = await _articleRepository.GetByIdAsync(id);
                    if (article != null)
                    {
                        await _articleRepository.DeleteAsync(id);
                        deletedCount++;
                    }
                }
                
                _logger.LogInformation("Batch deleted {Count} articles", deletedCount);
                return deletedCount;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error batch deleting articles");
                throw;
            }
        }

        /// <summary>
        /// 创建新文章
        /// 根据提供的文章数据传输对象创建新的文章实体，包括内容处理、SEO优化、状态管理等
        /// </summary>
        /// <param name="articleDto">文章创建数据传输对象，包含标题、内容、分类等信息</param>
        /// <returns>创建成功的文章数据传输对象</returns>
        /// <exception cref="ArgumentNullException">当articleDto为null时抛出</exception>
        /// <exception cref="InvalidOperationException">当文章创建失败时抛出</exception>
        public async Task<ArticleDto> CreateAsync(ArticleDto articleDto)
        {
            try
            {
                var article = new Article
                {
                    Title = articleDto.Title,
                    Slug = articleDto.Slug ?? GenerateSlug(articleDto.Title),
                    Summary = articleDto.Summary,
                    Content = articleDto.Content,
                    CategoryId = articleDto.CategoryId,
                    FeaturedImage = articleDto.FeaturedImageUrl,
                    Tags = articleDto.Tags,
                    Status = articleDto.Status,
                    Version = 1,
                    ViewCount = 0,
                    LikeCount = 0,
                    CommentCount = 0,
                    TopWeight = articleDto.IsSticky ? 1 : 0,
                    AllowComments = articleDto.AllowComments,
                    SeoTitle = articleDto.SeoTitle,
                    SeoKeywords = articleDto.SeoKeywords,
                    SeoDescription = articleDto.SeoDescription,
                    CustomFields = articleDto.CustomFields,
                    SortOrder = articleDto.SortOrder,
                    CreatedBy = articleDto.CreatedBy,
                    CreatedAt = DateTime.UtcNow,
                    UpdatedAt = DateTime.UtcNow
                };

                await _articleRepository.AddAsync(article);
                _logger.LogInformation("Article created successfully: {Id}", article.Id);
                
                return MapToDto(article);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error creating article");
                throw;
            }
        }

        /// <summary>
        /// 删除指定文章
        /// 根据文章ID执行删除操作，支持软删除策略
        /// </summary>
        /// <param name="id">要删除的文章ID</param>
        /// <returns>删除成功返回true，文章不存在返回false</returns>
        /// <exception cref="InvalidOperationException">当删除操作失败时抛出</exception>
        public async Task<bool> DeleteAsync(long id)
        {
            try
            {
                var article = await _articleRepository.GetByIdAsync(id);
                if (article == null)
                {
                    return false;
                }

                await _articleRepository.DeleteAsync(id);
                _logger.LogInformation("Article deleted successfully: {Id}", id);
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error deleting article {Id}", id);
                throw;
            }
        }

        /// <summary>
        /// 获取所有文章列表
        /// 检索系统中的所有文章，不分页显示，适用于管理员查看和数据导出场景
        /// </summary>
        /// <returns>所有文章的数据传输对象集合</returns>
        /// <exception cref="InvalidOperationException">当查询操作失败时抛出</exception>
        public async Task<IEnumerable<ArticleDto>> GetAllAsync()
        {
            try
            {
                var articles = await _articleRepository.GetAllAsync();
                return articles.Select(MapToDto).ToList();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting all articles");
                throw;
            }
        }

        public async Task<IEnumerable<ArticleDto>> GetByCategoryAsync(long categoryId)
        {
            try
            {
                var articles = await _articleRepository.GetByCategoryAsync(categoryId);
                return articles.Select(MapToDto).ToList();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting articles by category {CategoryId}", categoryId);
                throw;
            }
        }

        public async Task<ArticleDto?> GetByIdAsync(long id)
        {
            try
            {
                var article = await _articleRepository.GetByIdAsync(id);
                return article == null ? null : MapToDto(article);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting article by id {Id}", id);
                throw;
            }
        }

        public async Task<ArticleDto?> GetBySlugAsync(string slug)
        {
            try
            {
                var article = await _articleRepository.GetBySlugAsync(slug);
                return article == null ? null : MapToDto(article);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting article by slug {Slug}", slug);
                throw;
            }
        }

        public async Task<IEnumerable<ArticleDto>> GetLatestArticlesAsync(int count = 10)
        {
            try
            {
                var articles = await _articleRepository.GetLatestArticlesAsync(count);
                return articles.Select(MapToDto).ToList();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting latest articles");
                throw;
            }
        }

        public async Task<(IEnumerable<ArticleDto> Items, int TotalCount)> GetPagedAsync(int pageIndex, int pageSize, string? keyword = null, long? categoryId = null, byte? status = null, bool? isSticky = null)
        {
            try
            {
                var result = await _articleRepository.GetPagedAsync(pageIndex, pageSize, keyword, categoryId, status, isSticky);
                var dtos = result.Items.Select(MapToDto).ToList();
                return (dtos, result.TotalCount);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting paged articles");
                throw;
            }
        }

        public async Task<IEnumerable<ArticleDto>> GetPopularArticlesAsync(int count = 10)
        {
            try
            {
                var articles = await _articleRepository.GetPopularArticlesAsync(count);
                return articles.Select(MapToDto).ToList();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting popular articles");
                throw;
            }
        }

        public async Task<IEnumerable<ArticleDto>> GetStickyArticlesAsync(int count = 10)
        {
            try
            {
                var articles = await _articleRepository.GetStickyArticlesAsync(count);
                return articles.Select(MapToDto).ToList();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting sticky articles");
                throw;
            }
        }

        public async Task<bool> IncrementLikeCountAsync(long id)
        {
            try
            {
                var result = await _articleRepository.IncrementLikeCountAsync(id);
                if (result)
                {
                    _logger.LogInformation("Article like count incremented: {Id}", id);
                }
                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error incrementing like count for article {Id}", id);
                throw;
            }
        }

        public async Task<bool> IncrementViewCountAsync(long id)
        {
            try
            {
                var result = await _articleRepository.IncrementViewCountAsync(id);
                if (result)
                {
                    _logger.LogInformation("Article view count incremented: {Id}", id);
                }
                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error incrementing view count for article {Id}", id);
                throw;
            }
        }

        public async Task<bool> PublishAsync(long id)
        {
            try
            {
                var article = await _articleRepository.GetByIdAsync(id);
                if (article == null)
                {
                    return false;
                }

                article.Status = 1; // 发布状态
                article.PublishedAt = DateTime.UtcNow;
                article.UpdatedAt = DateTime.UtcNow;

                await _articleRepository.UpdateAsync(article);
                _logger.LogInformation("Article published successfully: {Id}", id);
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error publishing article {Id}", id);
                throw;
            }
        }

        public async Task<(IEnumerable<ArticleDto> Items, int TotalCount)> SearchAsync(string keyword, int pageIndex = 1, int pageSize = 20)
        {
            try
            {
                var result = await _articleRepository.SearchAsync(keyword, pageIndex, pageSize);
                var dtos = result.Items.Select(MapToDto).ToList();
                return (dtos, result.TotalCount);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error searching articles with keyword {Keyword}", keyword);
                throw;
            }
        }

        public async Task<bool> SetStickyAsync(long id, bool isSticky)
        {
            try
            {
                var article = await _articleRepository.GetByIdAsync(id);
                if (article == null)
                {
                    return false;
                }

                article.TopWeight = isSticky ? 1 : 0;
                article.UpdatedAt = DateTime.UtcNow;

                await _articleRepository.UpdateAsync(article);
                _logger.LogInformation("Article sticky status updated: {Id}, IsSticky: {IsSticky}", id, isSticky);
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error setting sticky status for article {Id}", id);
                throw;
            }
        }

        public async Task<bool> SlugExistsAsync(string slug, long? excludeId = null)
        {
            try
            {
                return await _articleRepository.SlugExistsAsync(slug, excludeId);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error checking if slug exists: {Slug}", slug);
                throw;
            }
        }

        public async Task<bool> UnpublishAsync(long id)
        {
            try
            {
                var article = await _articleRepository.GetByIdAsync(id);
                if (article == null)
                {
                    return false;
                }

                article.Status = 0; // 草稿状态
                article.UpdatedAt = DateTime.UtcNow;

                await _articleRepository.UpdateAsync(article);
                _logger.LogInformation("Article unpublished successfully: {Id}", id);
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error unpublishing article {Id}", id);
                throw;
            }
        }

        public async Task<ArticleDto> UpdateAsync(ArticleDto articleDto)
        {
            try
            {
                var article = await _articleRepository.GetByIdAsync(articleDto.Id);
                if (article == null)
                {
                    throw new ArgumentException($"Article with id {articleDto.Id} not found");
                }

                article.Title = articleDto.Title;
                article.Slug = articleDto.Slug ?? GenerateSlug(articleDto.Title);
                article.Summary = articleDto.Summary;
                article.Content = articleDto.Content;
                article.CategoryId = articleDto.CategoryId;
                article.FeaturedImage = articleDto.FeaturedImageUrl;
                article.Tags = articleDto.Tags;
                article.Status = articleDto.Status;
                article.Version = articleDto.Version;
                article.TopWeight = articleDto.IsSticky ? 1 : 0;
                article.AllowComments = articleDto.AllowComments;
                article.SeoTitle = articleDto.SeoTitle;
                article.SeoKeywords = articleDto.SeoKeywords;
                article.SeoDescription = articleDto.SeoDescription;
                article.CustomFields = articleDto.CustomFields;
                article.SortOrder = articleDto.SortOrder;
                article.UpdatedBy = articleDto.UpdatedBy;
                article.UpdatedAt = DateTime.UtcNow;

                await _articleRepository.UpdateAsync(article);
                _logger.LogInformation("Article updated successfully: {Id}", article.Id);
                
                return MapToDto(article);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error updating article");
                throw;
            }
        }

        public async Task<bool> UpdateStatusAsync(long id, byte status)
        {
            try
            {
                var article = await _articleRepository.GetByIdAsync(id);
                if (article == null)
                {
                    return false;
                }

                article.Status = status;
                article.UpdatedAt = DateTime.UtcNow;

                if (status == 1) // 发布状态
                {
                    article.PublishedAt = DateTime.UtcNow;
                }

                await _articleRepository.UpdateAsync(article);
                _logger.LogInformation("Article status updated: {Id}, Status: {Status}", id, status);
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error updating status for article {Id}", id);
                throw;
            }
        }

        #region Private Methods

        /// <summary>
        /// 将文章实体映射为DTO
        /// </summary>
        private static ArticleDto MapToDto(Article article)
        {
            return new ArticleDto
            {
                Id = article.Id,
                Title = article.Title,
                Slug = article.Slug,
                Summary = article.Summary,
                Content = article.Content,
                CategoryId = article.CategoryId ?? 0,
                AuthorId = article.CreatedBy,
                IsPublished = article.Status == 1,
                Views = article.ViewCount,
                Likes = article.LikeCount,
                Comments = article.CommentCount,
                Tags = article.Tags,
                FeaturedImageUrl = article.FeaturedImage,
                PublishedAt = article.PublishedAt,
                IsSticky = article.TopWeight > 0,
                AllowComments = article.AllowComments,
                CommentCount = article.CommentCount,
                ViewCount = article.ViewCount,
                LikeCount = article.LikeCount,
                SeoTitle = article.SeoTitle,
                SeoKeywords = article.SeoKeywords,
                SeoDescription = article.SeoDescription,
                CustomFields = article.CustomFields,
                SortOrder = article.SortOrder,
                Status = article.Status,
                Version = article.Version,
                CreatedBy = article.CreatedBy ?? 0,
                UpdatedBy = article.UpdatedBy ?? 0,
                CreatedAt = article.CreatedAt,
                UpdatedAt = article.UpdatedAt,
                // 导航属性将在需要时通过其他服务填充
                CreatorName = article.Creator?.RealName ?? article.Creator?.Username,
                UpdaterName = article.Updater?.RealName ?? article.Updater?.Username,
                CategoryName = article.Category?.Name
            };
        }

        /// <summary>
        /// 根据标题生成URL友好的别名
        /// </summary>
        private string GenerateSlug(string title)
        {
            if (string.IsNullOrWhiteSpace(title))
            {
                return Guid.NewGuid().ToString("N")[..8];
            }

            // 简化的slug生成逻辑
            var slug = title.ToLowerInvariant()
                           .Replace(" ", "-")
                           .Replace("_", "-")
                           .Trim('-');

            // 移除特殊字符
            var chars = slug.ToCharArray().Where(c => char.IsLetterOrDigit(c) || c == '-').ToArray();
            slug = new string(chars);

            // 确保不为空
            if (string.IsNullOrWhiteSpace(slug))
            {
                slug = Guid.NewGuid().ToString("N")[..8];
            }

            return slug;
        }

        #endregion
    }
}
